package com.atguigu.srb.core.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.atguigu.srb.common.result.ResponseEnum;
import com.atguigu.srb.common.util.Assert;
import com.atguigu.srb.core.enums.BorrowerStatusEnum;
import com.atguigu.srb.core.enums.LendStatusEnum;
import com.atguigu.srb.core.enums.ReturnMethodEnum;
import com.atguigu.srb.core.enums.TransTypeEnum;
import com.atguigu.srb.core.hfb.HfbConst;
import com.atguigu.srb.core.hfb.RequestHelper;
import com.atguigu.srb.core.mapper.*;
import com.atguigu.srb.core.pojo.bo.TransFlowBO;
import com.atguigu.srb.core.pojo.entity.*;
import com.atguigu.srb.core.pojo.vo.BorrowInfoApprovalVO;
import com.atguigu.srb.core.pojo.vo.BorrowerDetailVO;
import com.atguigu.srb.core.service.*;
import com.atguigu.srb.core.util.Amount1Helper;
import com.atguigu.srb.core.util.LendNoUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import net.sf.jsqlparser.expression.DateTimeLiteralExpression;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 标的准备表 服务实现类
 * </p>
 *
 * @author fan
 * @since 2021-11-22
 */
@Service
public class LendServiceImpl extends ServiceImpl<LendMapper, Lend> implements LendService {
    @Resource
    private BorrowInfoMapper borrowInfoMapper;
    @Resource
    private DictService dictService;
    @Resource
    private BorrowerMapper borrowerMapper;
    @Resource
    UserInfoMapper userInfoMapper;
    @Resource
    UserAccountMapper userAccountMapper;
    @Resource
    TransFlowService transFlowService;
    @Resource
    UserInfoService userInfoService;
    @Resource
    LendItemMapper lendItemMapper;
    @Resource
    LendReturnMapper lendReturnMapper;
    @Resource
    LendItemReturnMapper lendItemReturnMapper;

    @Override
    public Map<String, Object> showT(Long id) {
        //lendDetail{
        // lend{param},
        // borrower{}
        // }
        Lend lend = baseMapper.selectById(id);
        Integer returnMethod = lend.getReturnMethod();
        String returnMethodName = dictService.getNameByParentDictCodeAndValue("returnMethod", returnMethod);
        String msgByStatus = LendStatusEnum.getMsgByStatus(lend.getStatus());
        Map<String, Object> param = new HashMap<>();
        param.put("returnMethod", returnMethodName);
        param.put("status", msgByStatus);
        lend.setParam(param);

        BorrowerDetailVO borrowerDetailVO = new BorrowerDetailVO();
        String userId = lend.getUserId();
        QueryWrapper<Borrower> borrowerQueryWrapper = new QueryWrapper<>();
        borrowerQueryWrapper.eq("user_id", userId);
        Borrower borrower = borrowerMapper.selectOne(borrowerQueryWrapper);
        BeanUtils.copyProperties(borrower, borrowerDetailVO);

        borrowerDetailVO.setMarry(borrower.getMarry() ? "是" : "否");
        borrowerDetailVO.setSex(borrower.getSex() == 1 ? "男" : "女");

        String education = dictService.getNameByParentDictCodeAndValue("education", borrower.getEducation());
        borrowerDetailVO.setEducation(education);

        String industry = dictService.getNameByParentDictCodeAndValue("industry", borrower.getIndustry());
        borrowerDetailVO.setIndustry(industry);

        String income = dictService.getNameByParentDictCodeAndValue("income", borrower.getIncome());
        borrowerDetailVO.setIncome(income);

        String returnSource = dictService.getNameByParentDictCodeAndValue("returnSource", borrower.getReturnSource());
        borrowerDetailVO.setReturnSource(returnSource);

        String msgByStatus1 = BorrowerStatusEnum.getMsgByStatus(borrower.getStatus());
        borrowerDetailVO.setStatus(msgByStatus1);

        Map<String, Object> returnMap = new HashMap<>();
        returnMap.put("lend", lend);
        returnMap.put("borrower", borrowerDetailVO);

        return returnMap;
    }

    @Override
    public void createLend(BorrowInfoApprovalVO borrowInfoApprovalVO) {

        BorrowInfo borrowInfo = borrowInfoMapper.selectById(borrowInfoApprovalVO.getId());

        Lend lend = new Lend();
        BigDecimal serviceRate = borrowInfoApprovalVO.getServiceRate();
        lend.setServiceRate(serviceRate.divide(new BigDecimal("100"), 2, BigDecimal.ROUND_HALF_DOWN));
        lend.setStatus(LendStatusEnum.INVEST_RUN.getStatus());
        lend.setRealAmount(new BigDecimal("0"));
        lend.setInvestAmount(new BigDecimal("0"));
        lend.setInvestNum(new BigDecimal("0").intValue());
        //预期收益=借款总额*（月利率=年利率/12）
        BigDecimal monthRate = borrowInfoApprovalVO.getServiceRate().divide(new BigDecimal("1200"), 8, BigDecimal.ROUND_HALF_DOWN);
        BigDecimal amount = borrowInfo.getAmount();
        BigDecimal expectAmount = amount.multiply(monthRate);
        lend.setExpectAmount(expectAmount.multiply(new BigDecimal(borrowInfo.getPeriod())));// 平台预期收益
        lend.setAmount(borrowInfo.getAmount());
        lend.setBorrowInfoId(borrowInfo.getId());
        lend.setCheckAdminId(1l);
        lend.setCheckTime(LocalDateTime.now());
        lend.setCreateTime(LocalDateTime.now());

        // 放款(起息)开始的时间
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        LocalDate startDate = LocalDate.parse(borrowInfoApprovalVO.getLendStartDate(), dateTimeFormatter);
        lend.setLendStartDate(startDate);// 标的的审批通过时间，募资开始时间
        // 还款周期(期数)
        LocalDate endDate = startDate.plusMonths(borrowInfo.getPeriod());
        lend.setLendEndDate(endDate);// 标的的募资结束时间

        lend.setLendInfo(borrowInfoApprovalVO.getLendInfo());
        lend.setLendNo(LendNoUtils.getLendNo());// 标的单号(=订单号)
        lend.setPaymentAdminId(1l);
        lend.setLendYearRate(borrowInfo.getBorrowYearRate());
        lend.setLowestAmount(new BigDecimal(100));
        lend.setPeriod(borrowInfo.getPeriod());
        lend.setPublishDate(LocalDateTime.now());
        lend.setUserId(borrowInfo.getUserId());
        lend.setTitle(borrowInfoApprovalVO.getTitle());
        lend.setReturnMethod(borrowInfo.getReturnMethod());
        baseMapper.insert(lend);
    }

    @Override
    public List<Lend> getList() {
        List<Lend> list = baseMapper.selectList(null);
        for (Lend lend : list) {
            String msgByStatus = LendStatusEnum.getMsgByStatus(lend.getStatus());
            String returnMethod = dictService.getNameByParentDictCodeAndValue("returnMethod", lend.getReturnMethod());
            Map<String, Object> param = new HashMap<>();
            param.put("status", msgByStatus);
            param.put("returnMethod", returnMethod);
            lend.setParam(param);
        }
        return list;
    }

    @Override
    public BigDecimal getInterestCount(BigDecimal interestAmount, BigDecimal lendYearRate, Integer period, Integer returnMethod) {
        BigDecimal interestCount = new BigDecimal("0");
        //等额本息
        if (returnMethod == ReturnMethodEnum.ONE.getMethod()) {
            interestCount = Amount1Helper.getInterestCount(interestAmount, lendYearRate, period);
        } //等额本金
        if (returnMethod == ReturnMethodEnum.TWO.getMethod()) {
            interestCount = Amount1Helper.getInterestCount(interestAmount, lendYearRate, period);
        } //每月还息一次还本
        if (returnMethod == ReturnMethodEnum.THREE.getMethod()) {
            interestCount = Amount1Helper.getInterestCount(interestAmount, lendYearRate, period);
        } //一次还本还息
        if (returnMethod == ReturnMethodEnum.FOUR.getMethod()) {
            interestCount = Amount1Helper.getInterestCount(interestAmount, lendYearRate, period);
        }
        return interestCount;
    }

    @Override
    public void makeLoan(Long id) {
        Lend lend = baseMapper.selectById(id);
        Long lendId = lend.getId();
        //封装放款数据发送请求给汇付宝放款接口
        Map<String, Object> param = new HashMap<>();
        param.put("agentId", HfbConst.AGENT_ID);
        String lendNo = lend.getLendNo();
        param.put("agentProjectCode",lendNo);
        String userId2 = lend.getUserId();
        QueryWrapper<LendItem> lendItemQueryWrapper1 = new QueryWrapper<>();
        lendItemQueryWrapper1

                .eq("lend_id",lendId);
        LendItem lendItem1 = lendItemMapper.selectOne(lendItemQueryWrapper1);
        String lendItemNo = lendItem1.getLendItemNo();
        param.put("agentBillNo",lendItemNo);
        //平台收益
        BigDecimal serviceRate = new BigDecimal(String.valueOf(lend.getServiceRate()));
        BigDecimal divide = serviceRate.divide(new BigDecimal("12"),8, BigDecimal.ROUND_HALF_DOWN);
        param.put("mchFee", divide.multiply(new BigDecimal(lend.getPeriod())));
        param.put("note", TransTypeEnum.INVEST_UNLOCK);
        param.put("timestamp", RequestHelper.getTimestamp());
        String sign = RequestHelper.getSign(param);
        param.put("sign", sign);
        //发送请求,获取返回结果集 同步远程调用
        JSONObject jsonObject = RequestHelper.sendRequest(param, HfbConst.MAKE_LOAD_URL);
        Assert.isTrue("0000".equals(jsonObject.getString("resultCode")), ResponseEnum.LOAN_ERROR_FAIL);

        lend.setRealAmount(lend.getAmount());
        lend.setStatus(LendStatusEnum.PAY_RUN.getStatus());
        lend.setPaymentTime(LocalDateTime.now());
        baseMapper.updateById(lend);

        String userId = lend.getUserId();
        QueryWrapper<UserInfo> userInfoQueryWrapper = new QueryWrapper<>();
        userInfoQueryWrapper.eq("id", userId);
        UserInfo userInfo = userInfoMapper.selectOne(userInfoQueryWrapper);
        String bindCode = userInfo.getBindCode();

        BigDecimal total = new BigDecimal(jsonObject.getString("voteAmt"));
        userAccountMapper.updateAccount(bindCode, total, new BigDecimal(0));

        TransFlowBO transFlowBO = new TransFlowBO();
        transFlowBO.setAgentBillNo(jsonObject.getString("agentBillNo"));
        transFlowBO.setAmount(jsonObject.getBigDecimal("voteAmt"));
        transFlowBO.setBindCode(bindCode);
        transFlowBO.setMemo(jsonObject.getString("result_msg"));
        transFlowBO.setTransTypeEnum(TransTypeEnum.BORROW_BACK);
        transFlowService.saveTransFlow(transFlowBO);


        String borrowerBindCode = userInfoService.getBindCodeByUserId(userId);
        userAccountMapper.updateAccount(borrowerBindCode, jsonObject.getBigDecimal("voteAmt"), new BigDecimal("0"));
        transFlowService.saveTransFlow(new TransFlowBO(
                jsonObject.getString("agentBillNo"),
                borrowerBindCode,
                jsonObject.getBigDecimal("voteAmt"),
                TransTypeEnum.BORROW_BACK,
                "放款到账记录"
        ));


        QueryWrapper<LendItem> lendItemQueryWrapper = new QueryWrapper<>();
        lendItemQueryWrapper.eq("lend_id", lendId);
        List<LendItem> lendItems = lendItemMapper.selectList(lendItemQueryWrapper);
        for (LendItem lendItem : lendItems) {
            // 循环lend_item集合，修改投资人账户，生成交易流水
            String investUserId = lendItem.getInvestUserId();
            String investBindCode = userInfoService.getBindCodeByUserId(investUserId);
            userAccountMapper.updateAccount(investBindCode, new BigDecimal("0"), lendItem.getInvestAmount().negate());
            transFlowService.saveTransFlow(new TransFlowBO(
                    LendNoUtils.getTransNo(),
                    investBindCode,
                    jsonObject.getBigDecimal("voteAmt"),
                    TransTypeEnum.INVEST_UNLOCK,
                    "投资放款解冻记录"
            ));

        }
        repaymentPlan(lend,lendItems);
    }

    private void repaymentPlan(Lend lend, List<LendItem> lendItems) {
        Integer period = lend.getPeriod();
        // 循环投资期数，生成lend_return
        for (int i = 1; i <= period; i++) {
            System.out.println("2 根据期数生成借款人的还款计划");
            LendReturn lendReturn = new LendReturn();
            lendReturn.setUserId(lend.getUserId());
            lendReturn.setReturnMethod(lend.getReturnMethod());
            lendReturn.setCreateTime(LocalDateTime.now());
            lendReturn.setBorrowInfoId(lend.getBorrowInfoId());
            lendReturn.setBaseAmount(lend.getInvestAmount());
            lendReturn.setAmount(lend.getAmount());
            lendReturn.setStatus(0);
            lendReturn.setLendYearRate(lend.getLendYearRate());
            lendReturn.setOverdue(false);
            lendReturn.setLendId(lend.getId());
            lendReturn.setFee(new BigDecimal(0));
            lendReturn.setCurrentPeriod(i);
            lendReturn.setLast(false);
            lendReturnMapper.insert(lendReturn);// 新增还款计划
            // 再期数循环的基础之上，嵌套循环lend_item，生成lend_item_return
            BigDecimal totalPrincipal = new BigDecimal("0");
            BigDecimal totalInterest = new BigDecimal("0");
            for (LendItem lendItem : lendItems) {
                // 生成回款计划
                Map<String,BigDecimal> lendItemPIReturnMap =  returnInvest(lend,lendItem,lendReturn,i);// 当前投资人的本金和利息返回来
                totalPrincipal = totalPrincipal.add(lendItemPIReturnMap.get("lendItemPrincipal"));
                totalInterest = totalInterest.add(lendItemPIReturnMap.get("lendItemInterest"));
            }
            // 根据回款计划的本金和利息和(投资人)
            lendReturn.setPrincipal(totalPrincipal);// 当期本金和
            lendReturn.setInterest(totalInterest);// 当期利息和
            lendReturn.setTotal(totalPrincipal.add(totalInterest));// 当期总额
            lendReturnMapper.updateById(lendReturn);// 更新还款计划
        }
    }

    private Map<String, BigDecimal> returnInvest(Lend lend, LendItem lendItem, LendReturn lendReturn, int i) {
        // i本期的本金和利息的map
        Map<String,BigDecimal> lendItemPIReturnMap = new HashMap<>();

        System.out.println("3 根据期数*人数生成投资人的回款计划");

        // 根据金额，年利率，期数，还款方式计算每一期的还款
        Integer period = lend.getPeriod();
        BigDecimal investAmount = lendItem.getInvestAmount();
        BigDecimal lendYearRate = lend.getLendYearRate();
        Integer returnMethod = lend.getReturnMethod();

        // 获得当前投资人的每一期的本金和利息
        Map<Integer,BigDecimal> lendItemIReturnMap = new HashMap<>();// 每期利息
        Map<Integer,BigDecimal> lendItemPReturnMap = new HashMap<>();// 每期本金
        if (returnMethod.intValue() == ReturnMethodEnum.ONE.getMethod()) {
            //等额本息
            lendItemPReturnMap = Amount1Helper.getPerMonthPrincipal(investAmount, lendYearRate, period.intValue());
            lendItemIReturnMap = Amount1Helper.getPerMonthInterest(investAmount, lendYearRate, period.intValue());
        }
        if (returnMethod.intValue() == ReturnMethodEnum.TWO.getMethod()) {
            //等额本金
            lendItemPReturnMap = Amount1Helper.getPerMonthPrincipal(investAmount, lendYearRate, period.intValue());
            lendItemIReturnMap = Amount1Helper.getPerMonthInterest(investAmount, lendYearRate, period.intValue());
        }
        if (returnMethod.intValue() == ReturnMethodEnum.THREE.getMethod()) {
            //按期付息
            lendItemPReturnMap = Amount1Helper.getPerMonthPrincipal(investAmount, lendYearRate, period.intValue());
            lendItemIReturnMap = Amount1Helper.getPerMonthInterest(investAmount, lendYearRate, period.intValue());
        }
        if (returnMethod.intValue() == ReturnMethodEnum.FOUR.getMethod()) {
            //一次性
            lendItemPReturnMap = Amount1Helper.getPerMonthPrincipal(investAmount, lendYearRate, period.intValue());
            lendItemIReturnMap = Amount1Helper.getPerMonthInterest(investAmount, lendYearRate, period.intValue());
        }


        // 封装回款计划
        LendItemReturn lendItemReturn = new LendItemReturn();
        lendItemReturn.setStatus(0);
        lendItemReturn.setOverdue(false);
        lendItemReturn.setLendYearRate(lendYearRate);
        lendItemReturn.setReturnMethod(returnMethod);
        lendItemReturn.setInvestUserId(lendItem.getInvestUserId());
        lendItemReturn.setInvestAmount(lendItem.getInvestAmount());
        lendItemReturn.setFee(new BigDecimal("0"));// 免费
        lendItemReturn.setCurrentPeriod(i);
        lendItemReturn.setCreateTime(LocalDateTime.now());
        lendItemReturn.setLendReturnId(lendReturn.getId());
        lendItemReturn.setLendItemId(lendItem.getId());
        lendItemReturn.setLendId(lend.getId());
        lendItemReturn.setPrincipal(lendItemPReturnMap.get(i));
        lendItemReturn.setInterest(lendItemIReturnMap.get(i));
        lendItemReturn.setTotal(lendItemPReturnMap.get(i).add(lendItemIReturnMap.get(i)));
        lendItemReturnMapper.insert(lendItemReturn);

        // 返回本期的本金利息
        lendItemPIReturnMap.put("lendItemPrincipal",lendItemPReturnMap.get(i));
        lendItemPIReturnMap.put("lendItemInterest",lendItemIReturnMap.get(i));
        return lendItemPIReturnMap;
    }
}
